/**
 * @class Spark.Grid
 * @extends Spark.Component
 * <p>Grid 数据表格组件.
 * @author njq.niu@hand-china.com
 * @constructor
 * @param {Object} config 配置对象. 
 */
$S.Grid = Ext.extend($S.ViewComponent,{
//    focusCss:'',
    nbcls:'s_rq',
    ROW_HEIGHT:25,
    cellCls:'grid-cell',
    constructor: function(config){
        this.overId = null;
        this.selectedId = null;
        this.lockWidth = 0;
        $S.Grid.superclass.constructor.call(this,config);
    },
    initBind : function(){
    	if(this.bt) this.bind(this.bt)
    },
    initFocusElement : function(){
        this.focusEl = this.wb;
    },
    initComponent:function(config){
        $S.Grid.superclass.initComponent.call(this, config);
        var wp = this.wrap;
        this.wb = Ext.get(this.id+'_wrap');
        this.focusEl = this.wb;
        this.fb = this.wb.child('div[stype=grid.fb]');
        if(this.fb){
            this.uf = this.fb.child('div[stype=grid.uf]');
        }
        this.uc = wp.child('div[stype=grid.uc]');
        this.uh = wp.child('div[stype=grid.uh]');
        this.ub = wp.child('div[stype=grid.ub]'); 
        this.uht = wp.child('table[stype=grid.uht]'); 
        
        this.lc = wp.child('div[stype=grid.lc]'); 
        this.lh = wp.child('div[stype=grid.lh]');
        this.lb = wp.child('div[stype=grid.lb]');
        this.lht = wp.child('table[stype=grid.lht]'); 

        this.sp = wp.child('div[stype=grid.spliter]');
        Ext.getBody().insertFirst(this.sp)
        
        this.lockColumns =[],this.unlockColumns = [];
        this.lockWidth = 0,this.unlockWidth = 0;
        for(var i=0,l=this.columns.length;i<l;i++){
            var c = this.columns[i];
            if(c.lock === true){
                this.lockColumns.push(c);
                if(c.hidden !== true) this.lockWidth += c.width;
            }else{
                this.unlockColumns.push(c);
                if(c.hidden !== true) this.unlockWidth += c.width;
            }
        }
        this.columns = this.lockColumns.concat(this.unlockColumns);
        this.initTemplate();
    },
    processListener: function(ou){
    	$S.Grid.superclass.processListener.call(this, ou);
        if(this.listenMouseWheel)this.wb[ou]('mousewheel',this.onMouseWheel,this);
        this.wrap[ou]("mouseover", this.onMouseOver, this)
                 [ou]("mouseout", this.onMouseOut, this)
                 [ou]('mousedown',this.onMouseDown,this);
        this.ub[ou]('scroll',this.syncScroll, this)
//               [ou]('mousedown',this.onMouseDown, this)
               [ou]('dblclick',this.onDblclick, this);
        if(this.uht) this.uht[ou]('mousemove',this.onUnLockHeadMove, this);
        if(this.uh) {
        	this.uh[ou]('mousedown', this.onHeadMouseDown,this)
        	       [ou]('click', this.onHeadClick,this);
        }
        if(this.lb){
            this.lb[ou]('dblclick',this.onDblclick, this);
//                   [ou]('mousedown',this.onMouseDown, this);
        }
        if(this.lht) this.lht[ou]('mousemove',this.onLockHeadMove, this);
        if(this.lh) {
        	this.lh[ou]('mousedown', this.onHeadMouseDown,this)
        	       [ou]('click', this.onHeadClick,this);
        }
        
    },
    initEvents:function(){
        $S.Grid.superclass.initEvents.call(this);
        this.addEvents(
        /**
         * @event keydown
         * 键盘按下事件.
         * @param {Spark.Grid} grid 当前Grid组件.
         * @param {EventObject} e 鼠标事件对象.
         */
        'keydown',
        /**
         * @event dblclick
         * 鼠标双击事件.
         * @param {Spark.Grid} grid 当前Grid组件.
         * @param {Spark.Record} record 鼠标双击所在行的Record对象.
         * @param {Number} row 行号.
         * @param {String} 当前name.
         */
        'dblclick',
        /**
         * @event cellclick
         * 单元格点击事件.
         * @param {Spark.Grid} grid 当前Grid组件.
         * @param {Number} row 行号.
         * @param {String} 当前name.
         * @param {Spark.Record} record 鼠标点击所在单元格的Record对象.
         */
        'cellclick',
        /**
         * @event rowclick
         * 行点击事件.
         * @param {Spark.Grid} grid 当前Grid组件.
         * @param {Number} row 行号.
         * @param {Spark.Record} record 鼠标点击所在行的Record对象.
         */
        'rowclick',
        /**
         * @event editorShow
         * 编辑器显示后触发的事件.
         * @param {Spark.Grid} grid 当前Grid组件.
         * @param {Editor} grid 当前Editor组件.
         * @param {Number} row 行号.
         * @param {String} 当前name.
         * @param {Spark.Record} record 鼠标点击所在行的Record对象.
         */
        'editorshow',
        /**
         * @event nexteditorshow
         * 切换下一个编辑器的事件.
         * @param {Spark.Grid} grid 当前Grid组件.
         * @param {Number} row 行号.
         * @param {String} 当前name.
         */
        'nexteditorshow');
    },
    syncScroll : function(){
        this.hideEditor();
        if(this.uh) this.uh.dom.scrollLeft = this.ub.dom.scrollLeft;
        if(this.lb) this.lb.dom.scrollTop = this.ub.dom.scrollTop;
        if(this.uf) this.uf.dom.scrollLeft = this.ub.dom.scrollLeft;
    },
    //监听焦点对象的键盘事件
    onFocusKeyDown : function(e){
        var key = e.getKey(),ds = this.dataset;
        if(key == 38 || key == 40 || key == 33 || key == 34) {
            if(ds.loading == true) return;
            e.stopEvent();
            switch(e.getKey()){
                case 33://PAGEUP
                    ds.prePage();
                    break;
                case 34://PAGEDOWN
                    ds.nextPage();
                    break;
                case 38://UP
                    ds.pre();
                    break;
                case 40://DOWN
                    ds.next();
                    break;
            }
        }
        this.fireEvent('keydown', this, e)
    },
    processDataSetLiestener: function(ou){
        var ds = this.dataset;
        if(ds){
        	ds[ou]('ajaxfailed', this.onAjaxFailed, this);
            ds[ou]('metachange', this.onRefresh, this);//TODO: remove ?
            ds[ou]('update', this.onUpdate, this);
            ds[ou]('reject', this.onUpdate, this);
            ds[ou]('add', this.onAdd, this);
            ds[ou]('submit', this.onBeforSubmit, this);
            ds[ou]('submitfailed', this.onAfterSubmit, this);
            ds[ou]('submitsuccess', this.onAfterSubmit, this);
            ds[ou]('query', this.onBeforeLoad, this);
            ds[ou]('load', this.onLoad, this);
            ds[ou]('loadfailed', this.onAjaxFailed, this);
            ds[ou]('valid', this.onValid, this);
            ds[ou]('beforeremove', this.onBeforeRemove, this);
            ds[ou]('remove', this.onRemove, this);
            ds[ou]('clear', this.onLoad, this);
            ds[ou]('refresh',this.onRefresh,this);
            ds[ou]('fieldchange', this.onFieldChange, this);
            ds[ou]('indexchange', this.onIndexChange, this);
            ds[ou]('select', this.onSelect, this);
            ds[ou]('unselect', this.onUnSelect, this);
        }
    },
    bind : function(ds){
        if(typeof(ds)==='string'){
            ds = $(ds);
            if(!ds) return;
        }
        var sf = this;
        if(sf.autoPageSize == true){
            var ht = sf.ub.getStyle('height');
            ht = parseInt(ht.replaceAll('px',''));
            var pz = Math.floor((ht-23)/24);
            ds.psize = pz;
        }
        sf.dataset = ds;
        sf.processDataSetLiestener('on');
        this.onLoad();
        if(ds.current())this.onIndexChange(ds,ds.current())
//        Ext.onReady(function(){
//            sf.onLoad();
//        })
    },
    
    //REFINED
    initTemplate : function(){
    	//rowbox 
        this.rowBoxTpl = new Ext.Template('<td stype="{stype}" class="grid-rowbox" align="center" rid="{rid}">');
        //多选单选框
        this.cbTpl = new Ext.Template('<div class="{cellcls}" id="'+this.id+'_{name}_{rid}"><div class="s-ckb-box"></div></div>');        
        //行号        
        this.rowNumTpl = new Ext.Template('<td class="grid-rownumber" stype="rownum" rid="{rid}">');
        //普通单元格
        this.cellTpl = new Ext.Template('<td {tip} style="{visibility}" {align} dataindex="{name}" stype="cell" id="'+this.id+'_{name}_{rid}" class="{gridCell} {className}" rid="{rid}">');
    },
    getCheckBoxStatus: function(record, name) {
        var field = this.dataset.getField(name);
        if(field){
            var value = record.data[name];
            return (value && value == field.getPro('checkedValue')) ? 's-ckb-c' : 's-ckb-u';
        }
    },
    createTemplateData : function(col,record){
    	return {
            width:col.width-3,
            rid:record.id,
            gridCell:this.cellCls,
            tip: col.tip === 'true' ? 'tip="true"' : '',
            visibility: col.hidden === true ? 'visibility:hidden' : '',
            name:col.name
        }
    },
    
    //REFINED 
    //TODO:spark cell结构和aurora已经有差异
    createCell : function(col,record,includeTd){
        var data = this.createTemplateData(col,record),tdTpl = this.cellTpl,xtype = col.type,editor = this.getEditor(col,record),cls = '',html = '';
        if(editor!=''){
        	var edi = $S.CmpManager.get(editor);
        	//这里对于checkbox可能会存在问题
            if(edi && (edi instanceof $S.CheckBox)){
                xtype = 'cellcheck';
            }
        }
        if(xtype == 'rowcheck'||xtype == 'rowradio'){
        	var readonly="";
        	if(!this.dataset.execSelectFunction(record))readonly="_ro"
            tdTpl = this.rowBoxTpl;
            html = this.cbTpl.applyTemplate(Ext.apply(data,{
                stype: xtype == 'rowcheck'?'checkbox':'radio',
                cellcls: xtype == 'rowcheck'?'grid-ckb s-ckb'+readonly+'-u':'grid-radio s_radio'+readonly+'_u'
            }))
        } else if(xtype == 'cellcheck'){
            html = this.cbTpl.applyTemplate(Ext.apply(data,{
                align:'center',
                cellcls: 'grid-ckb ' + this.getCheckBoxStatus(record, col.name)
            }))
        } else if(xtype == 'rownumber'){
        	tdTpl = this.rowNumTpl;
            html = this.renderText(record,col,record.data[col.name],col.name)
        } else {
            var field = record.getField(col.name);
            if(field && Ext.isEmpty(record.data[col.name]) && record.isNew == true && field.get('required') == true){
                cls = cls + ' ' + this.nbcls
            }
            data = Ext.apply(data,{
                align:(col.align && col.align!= 'left') ? ('align="'+col.align+'"') : '',
                className:cls + ' ' + (col.className ? col.className : '')
            })
            html = this.renderText(record,col,record.data[col.name],col.name);
        }
        
        return includeTd==true ?[tdTpl.applyTemplate(data),html,'</td>'].join('') : html;
    },
    createRow : function(type, row, cols, item){
        var sb = [],css=this.parseCss(this.renderRow(item,row));
        sb.push('<tr height="'+this.ROW_HEIGHT+'" id="'+this.id+'$'+type+'-'+item.id+'" class="'+ (this.stripeRows ? (row % 2==0 ? '' : 'row-alt') : '')+css.cls+'"'+'style="'+css.style+'">');
        
        for(var i=0,l=cols.length;i<l;i++){
            var c = cols[i];
            sb.push(this.createCell(c,item,true))           
        }
        sb.push('</tr>');
        return sb.join('');
    },
    parseCss:function(css){
    	var style="",cls="";
    	if(Ext.isArray(css)){
    		for(var i=0;i<css.length;i++){
    			var _css=this.parseCss(css[i]);
    			style+=";"+_css.style;
    			cls+=" "+_css.cls;
    		}
    	}else if(typeof css=="string"){
    		isStyle=!!css.match(/^([^,:;]+:[^:;]+;)*[^,:;]+:[^:;]+;*$/);
    		cls=isStyle?"":css;
			style=isStyle?css:"";
    	}
    	return {style:style,cls:cls}
    	
    },
    //TODO: 没有value的时候不再更新是否能提高效率?
    renderText : function(record,col,value,name){
        var renderer = col.renderer;
        if(renderer){//&&!Ext.isEmpty(value)  去掉对value是否为空的判断
            var rder = $S.getFunction(renderer);
            if(rder == null){
                alert("未找到"+renderer+"方法!")
                return value;
            }
            value = rder.call(window,value,record, name);
            return (value === '') ? '&#160' : value;
        }
        return (value == null||value == '') ? '&#160' : $S.escapeHtml(value);
    },
    renderRow : function(record,rowIndex){
    	var renderer = this.rowRenderer,css=null;
        if(renderer){
            var rder = $S.getFunction(renderer);
            if(rder == null){
                alert("未找到"+renderer+"方法!")
                return css;
            }
            css = rder.call(window,record, rowIndex);
            return !css? '' : css;
        }
        return css ;
    },
    createTH : function(cols){
        var sb = [];
        sb.push('<tr class="grid-hl"');
        if(Ext.isIE6 || Ext.isIE7){
            sb.push(' style="display:none"');
        }
        sb.push('>');
        for(var i=0,l=cols.length;i<l;i++){
            var w = cols[i].width;
            if(cols[i].hidden === true) w = 0;
            sb.push('<th dataindex="'+cols[i].name+'" style="height:0px;width:'+w+'px"></th>');
        }
        sb.push('</tr>');
        return sb.join('');
    },
    onBeforeRemove : function(){
        $S.Masker.mask(this.wb,'正在删除数据...');
    },
    onBeforeLoad : function(){
        $S.Masker.mask(this.wb,'正在查询数据...');
    },
    onBeforSubmit : function(ds){
    	$S.Masker.mask(this.wb,'正在提交数据...');
    },
    onAfterSubmit : function(){
        $S.Masker.unmask(this.wb);
    },
    preLoad : function(){},
    onLoad : function(){
        this.selectRecord = null;
    	this.clearDomRef();
    	this.preLoad();
        var cb = Ext.fly(this.wrap).child('div[stype=grid.headcheck]');
        if(this.selectable && this.selectionModel=='multiple')this.setCheckBoxStatus(cb,false);
        if(this.lb)
        this.renderLockArea();
        this.renderUnLockAread();
//        if(focus !== false) this.focus.defer(10,this);//获取数据后的获得焦点,会引起其他编辑器无法编辑
        this.drawFootBar();
        $S.Masker.unmask(this.wb);
    },
    clearDomRef : function(){
    	this.selectlockTr = null;
        this.selectUnlockTr = null;
        
    },
    onAjaxFailed : function(res,opt){
        $S.Masker.unmask(this.wb);
    },
    onMouseWheel : function(e){
        e.stopEvent();
        if(this.editing == true) return;
    	var delta = e.getWheelDelta();
        if(delta > 0){
            this.dataset.pre();
        } else if(delta < 0){
            this.dataset.next();
        }
    },
    renderLockArea : function(){
        var sb = [];var cols = this.lockColumns;
        sb.push('<TABLE cellSpacing="0" stype="grid.lbt" cellPadding="0" border="0"  width="'+this.lockWidth+'"><TBODY>');
        sb.push(this.createTH(cols));
        for(var i=0,l=this.dataset.datas.length;i<l;i++){
            sb.push(this.createRow('l', i, cols, this.dataset.getAt(i)));
        }
        sb.push('</TBODY></TABLE>');
        sb.push('<DIV style="height:17px"></DIV>');
        this.lb.update(sb.join(''));
        this.lbt = this.lb.child('table[stype=grid.lbt]'); 
    },
    renderUnLockAread : function(){
        var sb = [];var cols = this.unlockColumns;
        sb.push('<TABLE cellSpacing="0" stype="grid.ubt" cellPadding="0" border="0" width="'+this.unlockWidth+'"><TBODY>');//width="'+this.unlockWidth+'" ??
        sb.push(this.createTH(cols));
        for(var i=0,l=this.dataset.datas.length;i<l;i++){
            sb.push(this.createRow('u', i, cols, this.dataset.getAt(i)));
        }
        sb.push('</TBODY></TABLE>');
        this.ub.update(sb.join(''));
        this.ubt = this.ub.child('table[stype=grid.ubt]'); 
    },
    isOverSplitLine : function(x){
        var v = 0;      
        var isOver = false;
        this.overColIndex = -1;
        var columns = this.columns;
        for(var i=0,l=columns.length;i<l;i++){
            var c = columns[i];
            if(c.hidden !== true) v += c.width;
            if(x < v+3 && x > v-3 && c.resizable != false){
                isOver = true;
                this.overColIndex = i;
                break;
            }
        }
        return isOver;
    },
    onRefresh : function(){
        this.onLoad();
    },
    onIndexChange:function(ds, r){
        var index = this.getDataIndex(r.id);
        if(index == -1)return;
        if(r != this.selectRecord){
            this.selectRow(index, false);
        }
    },    
    onAdd : function(ds,record,index){
        if(this.lb)
        var sb = [];var cols = [];
        var v = 0;
        var columns = this.columns;
        var row = this.dataset.datas.length-1;
        var css = this.parseCss(this.renderRow(record,row));
        if(this.lbt){
            var ltr = document.createElement("tr");
            ltr.id=this.id+'$l'+'-'+record.id;
            ltr.className= (this.stripeRows ? (row % 2==0 ? '' : 'row-alt') : '') +' '+css.cls;
            Ext.fly(ltr).set({'style':css.style,height:this.ROW_HEIGHT});
            for(var i=0,l=columns.length;i<l;i++){
                var col = columns[i];
                if(col.lock === true){
                    var td = document.createElement("td");
                    if(col.type == 'rowcheck' || col.type == 'rowradio') {
                        Ext.fly(td).set({
                        	'rid':record.id,
                        	'stype':col.type
                        })
                        td.className = 'grid-rowbox';
                        td.align = 'center';
                    } else if(col.type == 'rownumber') {
                        Ext.fly(td).set({
                        	'rid':record.id,
                        	'stype':'rownum'
                        })
                        td.className = 'grid-rownumber';
                    }else{
                    	td.id = this.id+'_' + col.name + '_' + record.id;
                        col.hidden === true ? (td.style.visibility='hidden') : '';
                        td.style.textAlign= col.align||'left';
                        td.className = this.cellCls + ' ' + (col.className ? col.className : '');    
                        Ext.fly(td).set({
                        	'dataindex':col.name,
                        	'rid':record.id,
                        	'stype':'cell'
                        });
                    }
                    var cell = this.createCell(col,record,false);
                    td.innerHTML = cell;
                    ltr.appendChild(td);
                }
            }
            this.lbt.dom.tBodies[0].appendChild(ltr);
        }
        
        var utr = document.createElement("tr");
        utr.id=this.id+'$u'+'-'+record.id;
        utr.className= (this.stripeRows ? (row % 2==0 ? '' : 'row-alt') : '') +' '+css.cls;
        Ext.fly(utr).set({'style':css.style,height:this.ROW_HEIGHT});
        for(var i=0,l=columns.length;i<l;i++){
            var col = columns[i];
            if(col.lock !== true){
                var td = document.createElement("td");
                td.id = this.id+'_' + col.name + '_' + record.id;
                col.hidden === true ? (td.style.visibility='hidden') : '';
                td.style.textAlign=col.align||'left';
                td.className = this.cellCls + ' ' + (col.className ? col.className : '');
                Ext.fly(td).set({
                    'dataindex':col.name,
                    'rid':record.id,
                    'stype':'cell'
                })
                var cell = this.createCell(col,record,false);
                td.innerHTML = cell;
                utr.appendChild(td);
            }
        }
        this.ubt.dom.tBodies[0].appendChild(utr);
    	this.setSelectStatus(record);
    },
    renderEditor : function(div,record,c,editor){
    	var cell = this.createCell(c,record,false);
    	div.parent().update(cell);
    },
    onUpdate : function(ds,record, name, value){
        this.setSelectStatus(record);
        Ext.each(this.columns,function(c){
            var td = Ext.get(this.id+'_'+c.name+'_'+record.id);
            if(td)
            if(c.name === name) {
                td.update(this.renderText(record,c, record.get(c.name), name));
            }else {
                if(c.renderer) {
                    var text = this.renderText(record,c, record.get(c.name), name);
                    if(text) td.update(text);
                }                            
            }
        },this)
        this.drawFootBar(name);
    },
    onValid : function(ds, record, name, valid){
        var c = this.findColByName(name);
//      if(c&&c.editor){
        if(c){
            var div = Ext.get(this.id+'_'+name+'_'+record.id);
            if(div) {
                if(valid == false){
                    div.addClass('s_ivd');
                }else{
                    div.removeClass([this.nbcls,'s_ivd']);
                }
            }
        }
    },
    onRemove : function(ds,record,index){
        var lrow = Ext.get(this.id+'$l-'+record.id);
        if(lrow)lrow.remove();
        
        var urow = Ext.get(this.id+'$u-'+record.id);
        if(urow)urow.remove();
        
        if(this.selectUnlockTr == Ext.get(this.id+'$u-'+record.id) && this.selectlockTr == Ext.get(this.id+'$l-'+record.id))
        this.clearDomRef();
        $S.Masker.unmask(this.wb);
    },
    onClear : function(){
        
    },
    onFieldChange : function(ds, record, field, type, value){
        switch(type){
           case 'required':
               var div = Ext.get(this.id+'_'+field.name+'_'+record.id);
               if(div) {
                   (value==true) ? div.addClass(this.nbcls) : div.removeClass(this.nbcls);
               }
               break;
        }
    },
    getDataIndex : function(rid){
        var index = -1;
        for(var i=0,l=this.dataset.datas.length;i<l;i++){
            var item = this.dataset.getAt(i);
            if(item.id == rid){
                index = i;
                break;
            }
        }
        return index;
    },
    onSelect : function(ds,record){
        var cb = Ext.get(this.id+'__'+record.id);
        if(cb && this.selectable && this.selectionModel=='multiple') {
            this.setCheckBoxStatus(cb, true);
            var tr = Ext.get(this.id+'$u-'+record.id);
            if(tr) {
                tr.removeClass('row-current');
                tr.addClass('row-selected');
            }
            tr = Ext.get(this.id+'$l-'+record.id);
            if(tr) {
                tr.removeClass('row-current');
                tr.addClass('row-selected');
            }
        }else{
            this.setRadioStatus(cb,true);
            this.dataset.locate((this.dataset.currentPage-1)*this.dataset.psize + this.dataset.indexOf(record) + 1)
        }
    },
    onUnSelect : function(ds,record){
        var cb = Ext.get(this.id+'__'+record.id);
        if(cb && this.selectable && this.selectionModel=='multiple') {
            this.setCheckBoxStatus(cb, false);
            var tr = Ext.get(this.id+'$u-'+record.id);
            if(tr) tr.removeClass('row-selected');
            tr = Ext.get(this.id+'$l-'+record.id);
            if(tr) tr.removeClass('row-selected');
        }else{
            this.setRadioStatus(cb,false);
        }
    },
    onDblclick : function(e){
        var target = Ext.fly(e.target).findParent('td[stype=cell]');
        if(target){
        	target = Ext.fly(target)
            var rid = target.getAttributeNS("","rid");
            var record = this.dataset.findById(rid);
            var row = this.dataset.indexOf(record);
            var name = target.getAttributeNS("","dataindex");
            this.fireEvent('dblclick', this, record, row, name)
        }
    },
    onMouseDown : function(e) {
        //先判断是不是grid的选择框,如果不是在判断是不是可编辑的cell
    	var target = Ext.fly(e.target);
        var td = target.findParent('td.grid-rowbox');
        if(!td) td = target.findParent('td.rownum');
        if(!td) {
            td = target.findParent('td.'+ this.cellCls);
        }
        if(td){
        	td = Ext.fly(td)
            var stype = td.getAttributeNS("","stype");
            var rid = td.getAttributeNS("","rid");
            if(stype=='cell'){
                this.stopFocus = true;
                var record = this.dataset.findById(rid);
                var row = this.dataset.indexOf(record);
                var name = td.getAttributeNS("","dataindex");
                this.hideEditor();//不隐藏的话,会先显示,再blur触发,这样当前的编辑器无法正常通过editorFunction获取到值
                this.showEditor(row,name);
                this.fireEvent('cellclick', this, row, name, record);
                this.fireEvent('rowclick', this, row, record);
                return;
            }else if (stype == 'rownum'){
                var record = this.dataset.findById(rid);
                var row = this.dataset.indexOf(record);
                if(record.id != this.selectedId) this.selectRow(row);
            } else if(stype=='checkbox'){ 
                var cb = Ext.get(this.id+'__'+rid);
                if(cb.hasClass('s-ckb-ro-u'))return;
                var checked = cb.hasClass('s-ckb-c');
                (checked) ? this.dataset.unSelect(rid) : this.dataset.select(rid);
            }else if(stype=='radio'){
            	var cb = Ext.get(this.id+'__'+rid);
                if(cb.hasClass('s_radio_ro_u'))return;
                this.dataset.select(rid);
            }
        }
        this.focus();
    },
    /**
     * 设置指定name列的标题.
     * 
     * @param {String} name 列的name
     * @param {String} prompt 标题信息
     */
    setColumnPrompt: function(name,prompt){
        var tds = Ext.DomQuery.select('td.grid-hc',this.wrap.dom);
        for(var i=0,l=tds.length;i<l;i++){
            var td = tds[i];
            var dataindex = Ext.fly(td).getAttributeNS("","dataindex");
            if(dataindex==name){
            	var div = Ext.fly(td).child('div');
            	div.update(prompt)
                break;
            }
        }
    },
    /**
     * 设置当前行的编辑器.
     * 
     * @param {String} name 列的name.
     * @param {String} editor 编辑器的id. ''空表示没有编辑器.
     */
    setEditor: function(name,editor){
        var col = this.findColByName(name);
        col.editor = editor;
    },
    getEditor : function(col,record){
        var ed = col.editor||'';
        if(col.editorFunction) {
            var ef = $S.getFunction(col.editorFunction);
            if(ef==null) {
                alert("未找到"+col.editorFunction+"方法!") ;
                return null;
            }
            ed = ef.call(window,record,col.name)
        }
        return ed;
    },
    /**
     * 显示编辑器.
     * @param {Number} row 行号
     * @param {String} name 当前列的name.
     */
    showEditor : function(row, name,callback){
        if(row == -1)return;
        var col = this.findColByName(name);
        if(!col)return;
        var record = this.dataset.getAt(row);
        if(!record)return;
        
        if(record.id != this.selectedId);
        this.selectRow(row);
        this.focusColumn(name);
        var editor = this.getEditor(col,record);
        this.setEditor(name, editor);
        if(editor!='' && ($(editor) instanceof $S.CheckBox)){
            var field = this.dataset.getField(name);
            if(field) {
                var cv = field.getPro('checkedvalue'),uv = field.getPro('uncheckedvalue'),v = record.get(name);
                record.set(name, v == cv ? uv : cv);
            }
        } else if(editor){
            var sf = this;
            setTimeout(function(){
                var dom = document.getElementById(sf.id+'_'+name+'_'+record.id);
                var xy = Ext.fly(dom).getXY();
                var v = record.get(name)
                sf.currentEditor = {
                    record:record,
                    ov:v,
                    name:name,
                    editor:$(editor)
                };
                var ed = sf.currentEditor.editor;
                if(ed){
                    ed.setHeight(Ext.fly(dom).getHeight()-1);//下边为1
                    ed.setWidth(Ext.fly(dom).getWidth()-1);//右边为1
                    ed.isEditor = true;
                    ed.isFireEvent = true;
                    ed.isHidden = false;
                    ed.setVisible(true);
                    ed.move(xy[0],xy[1]);
                    ed.bind(sf.dataset, name);
                    ed.render(record);
                    ed.focus();
                    if(ed.expand){
                        if(ed instanceof $S.Lov){
                            var f = sf.dataset.getField(name);
                            if(!record.get(f.getPro('valueField')))ed.expand();
                        }else{
                            ed.expand();
                        }
                    }
                    sf.editing = true;
                    ed.on('keydown', sf.onEidtorKeyDown,sf);
//                    ed.on('blur',sf.onEditorBlur, sf);
                    Ext.get(document.documentElement).on("mousedown", sf.onEditorBlur, sf);
                    if(callback)callback.call(window,ed)
                }
                sf.fireEvent('editorshow', sf, ed, row, name, record);
            },5)
        }
    },
    onEidtorKeyDown : function(editor,e){
        var keyCode = e.keyCode;
        //esc
        if(keyCode == 27) {
            editor.clearInvalid();
            editor.render(editor.binder.ds.current());
            this.hideEditor();
        }
        //enter
        if(keyCode == 13) {
            this.showNextEditor();
        }
        //tab
        if(keyCode == 9){
            e.stopEvent();
            this.showNextEditor();
        }
    },
    showNextEditor : function(){
        this.hideEditor();
        var callback = function(ed){
//            alert(ed)
        }
        if(this.currentEditor && this.currentEditor.editor){
            var ed = this.currentEditor.editor,ds = ed.binder.ds,
                fname = ed.binder.name,r = ed.record,
                row = ds.datas.indexOf(r),name=null;
            if(row!=-1){
                var cls = this.columns;
                var start = 0;
                for(var i = 0,l = cls.length; i<l; i++){
                    if(cls[i].name == fname){
                        start = i+1;
                    }
                }
                for(var i = start,l = cls.length; i<l; i++){
                    var col = cls[i];
                    var editor = this.getEditor(col,r);
                    if(editor!=''){
                        name =  col.name;
                        break;
                    }
                }
                if(name){
                    this.showEditor(row,name,callback);
                }else{
                    var nr = ds.getAt(row+1);
                    if(nr){
                        for(var i = 0,l = cls.length; i<l; i++){
                            var col = cls[i];
                            var editor = this.getEditor(col,r);
                            if(editor!=''){
                                name = col.name;
                                this.showEditor(row+1,name,callback);
                                break;
                            }
                        }
                    }
                }
            }
            this.fireEvent('nexteditorshow',this, row, name);
        }
    },
    /**
     * 指定行获取焦点.
     * @param {Number} row
     */
    doFocusRow : function(row){
        if(this.focusRow){
            var r = this.ROW_HEIGHT;
            var stop = this.ub.getScroll().top;
            if(row*r<stop){
                this.ub.scrollTo('top',row*r-1)
            }
            if((row+1)*r>(stop+this.ub.getHeight())){//this.ub.dom.scrollHeight
                var st = this.ub.dom.scrollWidth > this.ub.dom.clientWidth ? (row+1)*r-this.ub.getHeight() + 16 : (row+1)*r-this.ub.getHeight();
                this.ub.scrollTo('top',st)
            }
        }
    },
    focusColumn: function(name){
        var r = this.ROW_HEIGHT;
        var sleft = this.ub.getScroll().left;
        var ll = lr = lw = tw = 0;
        for(var i=0,l=this.columns.length;i<l;i++){
            var c = this.columns[i];
            if(c.name && c.name == name) {
//          if(c.name && c.name.toLowerCase() == name.toLowerCase()) {
                tw = c.width;
            }
            if(c.hidden !== true){
                if(c.lock === true){
                    lw += c.width;
                }else{
                    if(tw==0) ll += c.width;
                }
            }
        }
        lr = ll + tw;
        if(ll<sleft){
            this.ub.scrollTo('left',ll)
        }
        if((lr-sleft)>(this.width-lw)){
            this.ub.scrollTo('left',lr  - this.width + lw)
        }
//        this.focus();
    },
    /**
     * 隐藏当前编辑器
     */
    hideEditor : function(){
        if(this.currentEditor && this.currentEditor.editor && this.editing){
            var ed = this.currentEditor.editor;
            //ed.un('blur',this.onEditorBlur, this);
            var candHide = true;
            if(ed.canHide){
                candHide = ed.canHide();
            }
            
            if(candHide) {
                ed.un('keydown', this.onEidtorKeyDown,this);
                Ext.get(document.documentElement).un("mousedown", this.onEditorBlur, this);
                var ed = this.currentEditor.editor;
                ed.setVisible(false);
//                ed.move(-10000,-10000);
                ed.blur();
//                ed.onBlur();
                ed.isFireEvent = false;
                ed.isHidden = true;
                this.editing = false;
            }
        }
    },
    onEditorBlur : function(e){
        if(this.currentEditor && !this.currentEditor.editor.isEventFromComponent(e.target)) {           
            this.hideEditor();
        }
    },
    onLockHeadMove : function(e){
//      if(this.draging)return;
        var hmx = e.xy[0] - this.lht.getXY()[0];
        this.lh.setStyle('cursor', this.isOverSplitLine(hmx) ? "w-resize" : "default");
    },
    onUnLockHeadMove : function(e){
//      if(this.draging)return;
        var lw = 0;
        if(this.uht){
            lw = this.uht.getXY()[0] + this.uht.getScroll().left;
        }
        var hmx = e.xy[0] - lw + this.lockWidth;
        this.uh.setStyle('cursor',this.isOverSplitLine(hmx) ? "w-resize" : "default"); 
    },
    onHeadMouseDown : function(e){
        this.dragWidth = -1;
        if(this.overColIndex == undefined || this.overColIndex == -1) return;
        this.dragIndex = this.overColIndex;
        this.dragStart = e.getXY()[0];
        this.sp.setHeight(this.wrap.getHeight());
        this.sp.setVisible(true);
        this.sp.setStyle("top", this.wrap.getXY()[1]+"px")
        this.sp.setStyle("left", e.xy[0]+"px")
        Ext.get(document.documentElement).on("mousemove", this.onHeadMouseMove, this);
        Ext.get(document.documentElement).on("mouseup", this.onHeadMouseUp, this);
    },
    onHeadClick : function(e){
        var target = Ext.fly(e.target).findParent('td');
        var stype;
        if(target) {
            target = Ext.fly(target)
            stype = target.getAttributeNS("","stype");
            if(stype=='grid.head'){
                var index = target.getAttributeNS("","dataindex");
                var col = this.findColByName(index);
                if(col && col.sortable === true){
                	if(this.dataset.isModified()){
                        $S.showInfoMessage('提示', '有未保存数据!');
                        return;
                	}
                    var d = target.child('div');
                    var of = index;
                    var ot = '';
                    if(!this.currentSortTarget) {
                        var sf = this.dataset.defaultSortField;
                        if(sf){
                            var std = this.uht.child('td[dataindex='+sf+']');
                            if(!std) std = this.lht.child('td[dataindex='+sf+']');
                            if(std) this.currentSortTarget = std.child('div');
                        }
                    }
                    if(this.currentSortTarget){
                        var cst = Ext.fly(this.currentSortTarget)
                        cst.removeClass(['grid-asc','grid-desc']);
                    }
                    this.currentSortTarget = d;
                    if(col.sortType == 'desc') {
                        col.sortType = 'asc'
                        d.removeClass('grid-desc');
                        d.addClass('grid-asc');
                        ot = 'asc';
                    } else{
                        col.sortType = 'desc';
                        d.removeClass('grid-asc');
                        d.addClass('grid-desc');
                        ot = 'desc';
                    }
                    this.dataset.sort(of,ot);
                }
            } else if(stype=='grid.rowcheck'){
                var cb = target.child('div[stype=grid.headcheck]');
                var checked = cb.hasClass('s-ckb-c');
                this.setCheckBoxStatus(cb,!checked);
                if(!checked){
                    this.dataset.selectAll();
                }else{
                    this.dataset.unSelectAll();
                    var cr = this.dataset.current()
                    this.selectRow(this.dataset.indexOf(cr));
                }
            }
        }
    },
    setRadioStatus: function(el, checked){
        if(!checked){
            el.removeClass('s_radio_c');
            el.addClass('s_radio_u');
        }else{
            el.addClass('s_radio_c');
            el.removeClass('s_radio_u');
        }
    },
    setCheckBoxStatus: function(el, checked){
        if(!checked){
            el.removeClass('s-ckb-c');
            el.addClass('s-ckb-u');
        }else{
            el.addClass('s-ckb-c');
            el.removeClass('s-ckb-u');
        }
    },
    setSelectDisable:function(el){
    	if(this.selectable && this.selectionModel=='multiple'){
    		el.removeClass('s-ckb-c');
    		el.removeClass('s-ckb-u');
    		el.addClass('s-ckb-ro-u');
    	}else{
    		el.removeClass('s_radio_c');
    		el.removeClass('s_radio_u');
    		el.addClass('s_radio_ro_u');
    	}
    },
    setSelectEnable:function(el){
    	if(this.selectable && this.selectionModel=='multiple'){
    		el.removeClass('s-ckb-ro-u');
    		el.addClass('s-ckb-u');
    	}else{
    		el.removeClass('s_radio_ro_u');
    		el.addClass('s_radio_u');
    	}	
    },
    setSelectStatus:function(record){
    	if(this.dataset.selectfunction){
	    	var cb = Ext.get(this.id+'__'+record.id);
	    	if(!this.dataset.execSelectFunction(record)){
	    		 this.dataset.unSelect(record);
	    		 this.setSelectDisable(cb)
	    	}else{
	    		 this.setSelectEnable(cb);
	    	}
    	}
    },
    onHeadMouseMove: function(e){
//      this.draging = true
        e.stopEvent();
        this.dragEnd = e.getXY()[0];
        var move = this.dragEnd - this.dragStart;
        var c = this.columns[this.dragIndex];
        var w = c.width + move;
        if(w > 30 && w < this.width) {
            this.dragWidth = w;
            this.sp.setStyle("left", e.xy[0]+"px")
        }
    },
    onHeadMouseUp: function(e){
//      this.draging = false;
        Ext.get(document.documentElement).un("mousemove", this.onHeadMouseMove, this);
        Ext.get(document.documentElement).un("mouseup", this.onHeadMouseUp, this);      
        this.sp.setVisible(false);
        if(this.dragWidth != -1)
        this.setColumnSize(this.columns[this.dragIndex].name, this.dragWidth);
        this.syncScroll();
    },
    /**
     * 根据列的name获取列配置.
     * 
     * @param {String} name 列的name
     * @return {Object} col 列配置对象.
     */
    findColByName : function(name){
        var col;
        for(var i=0,l=this.columns.length;i<l;i++){
            var c = this.columns[i];
            if(c.name && c.name.toLowerCase() === name.toLowerCase()){
                col = c;
                break;
            }
        }
        return col;
    }, 
    /**
     * 选中高亮某行.
     * @param {Number} row 行号
     */
    selectRow : function(row, locate){
        var record = this.dataset.getAt(row);
        if(!record)return;
        this.selectedId = record.id;
        if(this.selectlockTr) this.selectlockTr.removeClass('row-current');
        if(this.selectUnlockTr) this.selectUnlockTr.removeClass('row-current');
        
        this.selectUnlockTr = Ext.get(this.id+'$u-'+record.id);
        if(this.selectUnlockTr && !this.selectUnlockTr.hasClass('row-selected')){
            this.selectUnlockTr.addClass('row-current');
        }
        this.selectlockTr = Ext.get(this.id+'$l-'+record.id);
        if(this.selectlockTr && !this.selectlockTr.hasClass('row-selected')){
            this.selectlockTr.addClass('row-current');
        }
        this.doFocusRow(row);
        
        var r = (this.dataset.currentPage-1)*this.dataset.psize + row+1;
        this.selectRecord = record
        if(locate!==false && r != null) {
//          this.dataset.locate(r);
            this.dataset.locate.defer(1, this.dataset,[r,false]);
        }
    },
    /**
     * 设置某列的宽度.
     * @param {String} name 列的name
     * @param {Number} size 列的宽度
     */
    setColumnSize : function(name, size){
        var columns = this.columns;
        var hth,bth,lw=0,uw=0;
        var wd = "width",px="px";
        for(var i=0,l=columns.length;i<l;i++){
            var c = columns[i];
            if(c.name && c.name === name){
                if(c.hidden === true) return;
                c.width = size;
                if(c.lock !== true){                    
                    hth = this.uh.child('th[dataindex='+name+']');
                    bth = this.ub.child('th[dataindex='+name+']');                  
                }else{                          
                    if(this.lh) hth = this.lh.child('th[dataindex='+name+']');
                    if(this.lb) bth = this.lb.child('th[dataindex='+name+']');
                    
                }
            }
            c.lock !== true ? (uw += c.width) : (lw += c.width);
        }
        var tds = Ext.DomQuery.select('td[dataindex='+name+']',this.wrap.dom);
        for(var i=0,l=tds.length;i<l;i++){
            var td = tds[i];
            var ce = Ext.fly(td).child('DIV.'+ this.cellCls);
            if(ce){
            	var sp =  1;
                Ext.fly(ce).setStyle(wd, Math.max(size-sp,0)+px);
            }
        }
        
        this.unlockWidth = uw;
        this.lockWidth = lw;
        if(hth) hth.setStyle(wd, size+px);
        if(bth) bth.setStyle(wd, size+px);
        if(this.fb){
            var ftd = this.fb.child('th[dataindex='+name+']');
            ftd.setStyle(wd, size+px);
            var uft = this.fb.child('table[stype=fb.ubt]');
            this.uf.setStyle(wd,Math.max(this.width - lw,0)+px);
            uft.setStyle(wd,uw+px);
            var lft = this.fb.child('table[stype=fb.lbt]');
            if(lft){
            var lf = this.fb.child('div[stype=grid.lf]');
                lf.setStyle(wd,(lw-1)+px);
                lft.setStyle(wd,lw+px);
            }
        }
        
        if(this.lc){
//            var lcw = Math.max(lw-1,0);
            var lcw = Math.max(lw,0);
            this.lc.setStyle(wd,lcw+px);
            this.lc.setStyle('display',lcw==0 ? 'none' : '');
        }
        if(this.lht)this.lht.setStyle(wd,lw+px);
        if(this.lbt)this.lbt.setStyle(wd,lw+px);
        this.uc.setStyle(wd, Math.max(this.width - lw,0)+px);
        this.uh.setStyle(wd,Math.max(this.width - lw,0)+px);
        this.ub.setStyle(wd,Math.max(this.width - lw,0)+px);
        this.uht.setStyle(wd,uw+px);
        if(this.ubt)this.ubt.setStyle(wd,uw+px);
        this.syncSize();
    },
    drawFootBar : function(objs){
    	if(!this.fb) return;
    	objs = [].concat((objs) ? objs : this.columns);
    	var sf = this;
    	Ext.each(objs, function(obj) {
    		var col = typeof(obj)==='string' ? sf.findColByName(obj) : obj;
            if(col&&col.footerrenderer){
                var name = col.name;
                var fder = $S.getFunction(col.footerrenderer);
                if(fder == null){
                    alert("未找到"+col.footerrenderer+"方法!")
                    return;
                }
                var v = fder.call(window,sf.dataset.datas, name);
                var t = sf.fb.child('td[dataindex='+name+']');
                t.update(v)
            }
    	});
    	
    },
    syncSize : function(){
        var lw = 0;
        for(var i=0,l=this.columns.length;i<l;i++){
            var c = this.columns[i];
            if(c.hidden !== true){
                if(c.lock === true){
                    lw += c.width;
                }
            }
        }
        if(lw !=0){
            var us = this.width -lw;
            this.uc.setWidth(us);
            this.uh.setWidth(us);
            this.ub.setWidth(us);
        }
    },
    /**
     * 显示某列.
     * 
     * @param {String} name 列的name
     */
    showColumn : function(name){
        var col = this.findColByName(name);
        if(col){
            if(col.hidden === true){
                delete col.hidden;
                this.setColumnSize(name, col.hiddenWidth);
                delete col.hiddenWidth;
//              if(!Ext.isIE){
                    var tds = Ext.DomQuery.select('td[dataindex='+name+']',this.wrap.dom);
                    for(var i=0,l=tds.length;i<l;i++){
                        var td = tds[i];
                        Ext.fly(td).show();
                    }
//              }
            }
        }   
    },
    /**
     * 隐藏某列.
     * 
     * @param {String} name 列的name;
     */
    hideColumn : function(name){
        var col = this.findColByName(name);
        if(col){
            if(col.hidden !== true){
                col.hiddenWidth = col.width;
                this.setColumnSize(name, 0, false);
//              if(!Ext.isIE){
                    var tds = Ext.DomQuery.select('td[dataindex='+name+']',this.wrap.dom);
                    for(var i=0,l=tds.length;i<l;i++){
                        var td = tds[i];
                        Ext.fly(td).hide();
                    }
//              }
                col.hidden = true;
            }
        }       
    },
    setWidth: function(w){
    	if(this.width == w) return;
        this.width = w;
        this.wrap.setWidth(w);
        var tb = $S.CmpManager.get(this.id+'_tb')
        if(tb)tb.setWidth(w);
        var nb = $S.CmpManager.get(this.id+'_navbar')
        if(nb)nb.setWidth(w);
        if(this.fb) this.fb.setWidth(w);
        var bw = w-this.lockWidth
        this.uc.setWidth(bw);
        if(this.uh)this.uh.setWidth(bw);
        this.ub.setWidth(bw);
        if(this.uf) this.uf.setWidth(bw);
    },
    setHeight: function(h){
    	if(this.height == h) return;
        this.height = h;
        var tb = $S.CmpManager.get(this.id+'_tb');
        if(tb)h-=this.ROW_HEIGHT;
        var nb = $S.CmpManager.get(this.id+'_navbar');
        if(nb)h-=this.ROW_HEIGHT;
        if(this.fb)h-=this.ROW_HEIGHT;
        this.wrap.setHeight(h);
        var bh = h - this.maxRow*this.ROW_HEIGHT;
        if(this.lb)this.lb.setHeight(bh)
        this.ub.setHeight(bh)
    },
    deleteSelectRows: function(win){
        var selected = [].concat(this.dataset.getSelected());
        if(selected.length >0){
            this.dataset.remove(selected);
        }
        win.close();  
    },
    remove: function(){
        var selected = this.dataset.getSelected();
        if(selected.length >0) {
            $S.showConfirm('确认','如果删除，这些数据将无法恢复。您确定吗?',this.deleteSelectRows.createDelegate(this),null, 350);    
        }else{
            $S.showInfoMessage('提示','没有选中任何数据，请重新选择!');
        }
    },
    destroy: function(){
        Ext.get(document.documentElement).un("mousedown", this.onEditorBlur, this);
        $S.Grid.superclass.destroy.call(this);
        this.processDataSetLiestener('un');
        this.sp.remove();
        delete this.sp;
    }
});
$S.Grid.revision='$Rev: 103 $';